﻿using System;
using System.Diagnostics;
using System.DirectoryServices;
using System.IO;
using System.Linq;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Forms;
using System.Windows.Input;
using Finder.Data;
using Finder.Properties;
using Finder.Utilities.Helpers;
using Finder.Utilities.KeyCapture;
using Microsoft.Office.Interop.Outlook;
using Application = System.Windows.Application;
using ContextMenu = System.Windows.Forms.ContextMenu;
using Exception = System.Exception;
using MenuItem = System.Windows.Forms.MenuItem;
using Outlook = Microsoft.Office.Interop.Outlook;

namespace Finder
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow
    {
        /// <summary>
        /// Key stack for the app.
        /// </summary>
        private readonly KeyIdentifier[] keyStack = new KeyIdentifier[2];

        /// <summary>
        /// Initializes a new instance of the <see cref="MainWindow"/> class.
        /// </summary>
        public MainWindow()
        {
            if (OtherInstancesRunning())
            {
                this.Close();
            }

            InitializeComponent();


            this.Closed += this.MainWindowClosed;
            this.Deactivated += this.MainWindowDeactivated;
            this.Loaded += this.MainWindowLoaded;

            Stream iconStream = Application.GetResourceStream(new Uri("pack://application:,,,/Finder;component/search_business_user.ico")).Stream;

            NotifyIcon notifyIcon = new NotifyIcon
                                        {
                                            Visible = true,
                                            Icon = new System.Drawing.Icon(iconStream)
                                        };

            notifyIcon.DoubleClick += this.NotifyIconDoubleClick;
            MenuItem[] mi = new MenuItem[2];
            mi[0] = new MenuItem(
                "Close",
                delegate
                    {
                        this.Close();
                    });

            mi[1] = new MenuItem(
                "Config",
                delegate
                    {
                        new Config().ShowDialog();
                    });

            notifyIcon.ContextMenu = new ContextMenu(mi);
        }

        /// <summary>
        /// Gets or sets a value indicating whether this <see cref="MainWindow"/> is open.
        /// </summary>
        /// <value><c>true</c> if open; otherwise, <c>false</c>.</value>
        protected bool Open { get; set; }

        /// <summary>
        /// Gets or sets the kh.
        /// </summary>
        /// <value>The KeyboardHook.</value>
        protected KeyboardHook Kh { get; set; }

        /// <summary>
        /// Gets or sets the first click.
        /// </summary>
        /// <value>The first click.</value>
        protected DateTime FirstClick { get; set; }

        /// <summary>
        /// Gets or sets the employees.
        /// </summary>
        /// <value>The employees.</value>
        protected IQueryable<DEL_TB_Pracownik> Employees { get; set; }

        /// <summary>
        /// Gets or sets the elements on list count.
        /// </summary>
        /// <value>The elements on list count.</value>
        protected int ElementsOnListCount { get; set; }

        /// <summary>
        /// Gets the list colappsed corner radius.
        /// </summary>
        /// <value>The list colappsed.</value>
        protected CornerRadius ListColappsed
        {
            get
            {
                return new CornerRadius(5.2);
            }
        }

        /// <summary>
        /// Gets the list visible corner radius.
        /// </summary>
        /// <value>The list visible.</value>
        protected CornerRadius ListVisible
        {
            get
            {
                return new CornerRadius(5.2, 5.2, 0, 0);
            }
        }

        /// <summary>
        /// Others the instances running.
        /// </summary>
        /// <returns>Bool if other instances were detected.</returns>
        private static bool OtherInstancesRunning()
        {
            return Process.GetProcesses().Where(x => x.ProcessName == "Finder").Count() > 1;
        }

        /// <summary>
        /// Shows the finder.
        /// </summary>
        private void ShowFinder()
        {
            this.Show();
            this.WindowState = WindowState.Normal;
            this.WindowStartupLocation = WindowStartupLocation.CenterScreen;
            this.BringIntoView();
            this.Topmost = true;
        }

        /// <summary>
        /// Hides the finder.
        /// </summary>
        private void HideFinder()
        {
            this.Hide();
            this.WindowState = WindowState.Minimized;
        }

        /// <summary>
        /// Determines the visibility of email sending button, based on wether specified user has email or not.
        /// </summary>
        /// <param name="prcEMail">Email adress for the user.</param>
        /// <returns>Visibility based on email adress being set or not.</returns>
        private static Visibility Visible(string prcEMail)
        {
            return !string.IsNullOrEmpty(prcEMail)
                       ? Visibility.Visible
                       : Visibility.Hidden;
        }

        private void AD()
        {
            DirectoryEntry directoryEntry = new DirectoryEntry("LDAP://virgo.kruk-inkaso.com.pl/DC=kruk-inkaso,DC=com,DC=pl");
            DirectorySearcher dS = new DirectorySearcher(directoryEntry);
            dS.Filter = "(ObjectCategory=user)";
            dS.SearchScope = SearchScope.Subtree;
            SearchResultCollection searchResultCollection = dS.FindAll();
            foreach (SearchResult result in searchResultCollection)
            {
                string username = result.GetDirectoryEntry().Name;
            }
        }

        /// <summary>
        /// Handles the Loaded event of the MainWindow control.
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see cref="System.Windows.RoutedEventArgs"/> instance containing the event data.</param>
        private void MainWindowLoaded(object sender, RoutedEventArgs e)
        {
//            AD();

            this.FirstClick = DateTime.Now;
            DelfinDataContext delfinDataContext = new DelfinDataContext();
            this.Employees = from q in delfinDataContext.DEL_TB_Pracowniks
                             where q.prc_Usuniety == false
                             select q;

            this.SetListVisiblilityOptions(Visibility.Collapsed);
            this.Kh = new KeyboardHook(KeyboardHook.Parameters.PassAllKeysToNextApp);
            this.Kh.KeyIntercepted += this.KhKeyIntercepted;

            double primaryScreenHeight = SystemParameters.PrimaryScreenHeight;
            this.ElementsOnListCount = (int)Math.Round(Math.Floor(((primaryScreenHeight / 2) - 100) / 60), 0);
        }

        /// <summary>
        /// Handles the Deactivated event of the MainWindow control.
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see cref="System.EventArgs"/> instance containing the event data.</param>
        private void MainWindowDeactivated(object sender, EventArgs e)
        {
            this.HideFinder();
        }

        /// <summary>
        /// Handles the Closed event of the MainWindow control.
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see cref="System.EventArgs"/> instance containing the event data.</param>
        private void MainWindowClosed(object sender, EventArgs e)
        {
            this.Kh.Dispose();
        }

        /// <summary>
        /// Handles the DoubleClick event of the notifyIcon control.
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see cref="System.EventArgs"/> instance containing the event data.</param>
        private void NotifyIconDoubleClick(object sender, EventArgs e)
        { 
            this.ShowFinder();
        }

        /// <summary>
        /// KH_s the key intercepted.
        /// </summary>
        /// <param name="e">The <see cref="KeyboardHook.KeyboardHookEventArgs"/> instance containing the event data.</param>
        private void KhKeyIntercepted(KeyboardHook.KeyboardHookEventArgs e)
        {
            // Esc key detected
            if (e.KeyCode == 27 && this.WindowState == WindowState.Normal)
            {
                this.HideFinder();
                return;
            }
            
            if (this.keyStack[0] == null)
            {
                this.keyStack[0] = new KeyIdentifier(e.KeyCode, e.KeyName);
            }
            else
            {
                if (this.keyStack[0].KeyCode != e.KeyCode)
                {
                    this.keyStack[1] = new KeyIdentifier(e.KeyCode, e.KeyName);
                }
            }

            if (this.HotKeyDetected())
            {
                this.ShowFinder();
            }

            if (this.HotKeySet())
            {
                this.ClearHotKey();
            }
        }

        /// <summary>
        /// Clears the hot key.
        /// </summary>
        private void ClearHotKey()
        {
            this.keyStack[0] = this.keyStack[1] = null;
        }

        /// <summary>
        /// Hots the key set.
        /// </summary>
        /// <returns>True or false.</returns>
        private bool HotKeySet()
        {
            return (this.keyStack[0] != null && this.keyStack[1] != null);
        }

        /// <summary>
        /// Hots the key detected.
        /// </summary>
        /// <returns>true or false.</returns>
        private bool HotKeyDetected()
        {
            try
            {
                string[] hotKeyCfg = Settings.Default.HotKeyCode.Split('|');
                int[] hotKey = new[]
                                   {
                                       Convert.ToInt32(hotKeyCfg[0]), Convert.ToInt32(hotKeyCfg[1])
                                   };

                KeyIdentifier[] keyIdentifiers = new KeyIdentifier[2];
                keyIdentifiers[0] = new KeyIdentifier(hotKey[0], "Config Key 1");
                keyIdentifiers[1] = new KeyIdentifier(hotKey[1], "Config Key 2");
                return this.keyStack.SequenceEqual(keyIdentifiers);
            }
            catch(Exception ex)
            {
                return false;
            }
        }

        /// <summary>
        /// Handles the TextChanged event of the txtQuery control.
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see cref="System.Windows.Controls.TextChangedEventArgs"/> instance containing the event data.</param>
        private void TxtQueryTextChanged(object sender, TextChangedEventArgs e)
        {
            this.PerformSearch();
        }

        /// <summary>
        /// Based on query provided in txtQuery control, this method will lookd for suitable matches.
        /// </summary>
        private void PerformSearch()
        {
            if (LbxResults != null)
            {
                string txt = txtQuery.Text;

                if (!string.IsNullOrEmpty(txt) && !string.IsNullOrWhiteSpace(txt))
                {
                    var p = from q in this.Employees
                            where
                                q.prc_EMail.Contains(txt) ||
                                q.prc_Nazwa.Contains(txt) ||
                                q.prc_Opis.Contains(txt) ||
                                q.prc_Skrot.Contains(txt) ||
                                q.prc_Telefon.Contains(txt)
                            select new
                            {
                                Name = q.prc_Nazwa,
                                Desc = q.prc_Opis,
                                Wew = q.prc_Telefon,
                                Kom = q.prc_TelefonKomorkowy,
                                Id = q.prc_ID,
                                Email = q.prc_EMail,
                                EmailVisibility = Visible(q.prc_EMail)
                            };

                    if (p.Any())
                    {
                        this.SetListVisiblilityOptions(Visibility.Visible);
                        IQueryable queryable;

                        if(p.Count() > this.ElementsOnListCount)
                        {
                            queryable = p.Skip(0).Take(this.ElementsOnListCount - 1);
                            this.OptionsBottom.Visibility = Visibility.Visible;
                        }
                        else
                        {
                            queryable = p.Skip(0).Take(this.ElementsOnListCount);
                            this.OptionsBottom.Visibility = Visibility.Collapsed;
                        }

                        LbxResults.ItemsSource = queryable;
                    }
                    else
                    {
                        this.SetListVisiblilityOptions(Visibility.Collapsed);
                    }
                }
                else
                {
                    this.SetListVisiblilityOptions(Visibility.Collapsed);
                }
            }
        }

        /// <summary>
        /// Sets the list visiblility options.
        /// </summary>
        /// <param name="visibility">The visibility.</param>
        private void SetListVisiblilityOptions(Visibility visibility)
        {
            brd.Visibility = visibility;

            if (visibility == Visibility.Collapsed)
            {
                this.mask.CornerRadius = this.ListColappsed;
                return;
            }

            this.mask.CornerRadius = this.ListVisible;
        }

        /// <summary>
        /// Called when [send email] is executed by the command.
        /// </summary>
        /// <param name="sender">The sender.</param>
        /// <param name="e">The <see cref="System.Windows.Input.ExecutedRoutedEventArgs"/> instance containing the event data.</param>
        private void OnSendEmail(object sender, ExecutedRoutedEventArgs e)
        {
            int personId = (int)e.Parameter;

            string adressForOutlook = Settings.Default.EmailToOutlook
                                          ? this.Employees.Where(x => x.prc_ID == personId).First().prc_EMail
                                          : this.Employees.Where(x => x.prc_ID == personId).First().prc_Nazwa;

            try
            {
                Outlook.Application objOutlook = new Outlook.Application();
                MailItem item = (MailItem) objOutlook.CreateItem(Outlook.OlItemType.olMailItem);
                item.To = adressForOutlook;
                item.Display();
            }
            catch
            {
                // Godzilla eat it!
            }
        }

        /// <summary>
        /// Called when [open contact details page].
        /// </summary>
        /// <param name="sender">The sender.</param>
        /// <param name="e">The <see cref="System.Windows.Input.ExecutedRoutedEventArgs"/> instance containing the event data.</param>
        private void OnOpenContactDetailsPage(object sender, ExecutedRoutedEventArgs e)
        {
            string employeeName = this.Employees.Where(x => x.prc_ID == (int)e.Parameter).First().prc_Nazwa;
            Process.Start(new ProcessStartInfo("http://www.instrukcja.kruk-inkaso.com.pl/images/Intranet/png/" + employeeName + ".png"));
        }

        /// <summary>
        /// Windows the activated.
        /// </summary>
        /// <param name="sender">The sender.</param>
        /// <param name="e">The <see cref="System.EventArgs"/> instance containing the event data.</param>
        private void WindowActivated(object sender, EventArgs e)
        {
            FocusHelper.Focus(this.txtQuery);
        }

        /// <summary>
        /// BTNs the next page mouse left button up.
        /// </summary>
        /// <param name="sender">The sender.</param>
        /// <param name="e">The <see cref="System.Windows.Input.MouseButtonEventArgs"/> instance containing the event data.</param>
        private void BtnNextPageMouseLeftButtonUp(object sender, MouseButtonEventArgs e)
        {

        }
    }
}
